package ru.neoflex.jedit.plugin.domain.autocomplete;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.xpath.DefaultXPath;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.SAXException;
import ru.neoflex.jedit.plugin.utils.Assert;
import ru.neoflex.jedit.plugin.utils.XmlUtils;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.*;
import java.util.*;

@XStreamAlias("XhtmlAutocomplete")
public class XhtmlAutocompleteSettings {
    private List<Tag> tags = new ArrayList<Tag>();

    public Tag getTagByName(String name) {
        for (Tag tag : tags) {
            if (tag.getName().equals(name)) {
                return tag;
            }
        }

        return null;
    }

    @XStreamAlias("tag")
    public static class Tag {
        private String name;
        private List<TagAttribute> attributes = new ArrayList<TagAttribute>();
        private String usageExample;

        public List<TagAttribute> getMandatoryAttributes() {
            List<TagAttribute> result = new ArrayList<TagAttribute>();
            for (TagAttribute attr : attributes) {
                if (attr.getMandatory()) {
                    result.add(attr);
                }
            }
            return result;
        }

        public List<TagAttribute> getNotMandatoryAttributes() {
            List<TagAttribute> result = new ArrayList<TagAttribute>();
            for (TagAttribute attr : attributes) {
                if (!attr.getMandatory()) {
                    result.add(attr);
                }
            }
            return result;
        }

        public String toString() {
            return name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public List<TagAttribute> getAttributes() {
            return attributes;
        }

        public void setAttributes(List<TagAttribute> attributes) {
            this.attributes = attributes;
        }

        public String getUsageExample() {
            return usageExample;
        }

        public void setUsageExample(String usageExample) {
            this.usageExample = usageExample;
        }
    }

    @XStreamAlias("attribute")
    public static class TagAttribute {
        @XStreamAsAttribute
        private String name;
        @XStreamAsAttribute
        private Boolean mandatory;
        @XStreamAsAttribute
        private String description;

        public String toString() {
            return name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Boolean getMandatory() {
            return mandatory;
        }

        public void setMandatory(Boolean mandatory) {
            this.mandatory = mandatory;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }
    }

    public List<Tag> getTags() {
        return tags;
    }

    public void setTags(List<Tag> tags) {
        this.tags = tags;
    }

    public static String DEFAULT_CONFIG_NAME = "xhtml.xml";

    public static void saveToXml(XhtmlAutocompleteSettings settings, String filename) throws IOException {
        Assert.notNull(settings);
        Assert.notBlank(filename);

        XStream xs = new XStream();
        xs.processAnnotations(new Class[]{XhtmlAutocompleteSettings.class, Tag.class, TagAttribute.class});
        xs.toXML(settings, new FileWriter(filename));
    }

    public static XhtmlAutocompleteSettings loadFromXml(String filename) throws FileNotFoundException {
        Assert.notBlank(filename);

        XStream xs = new XStream();
        xs.processAnnotations(new Class[]{XhtmlAutocompleteSettings.class, Tag.class, TagAttribute.class});
        return (XhtmlAutocompleteSettings) xs.fromXML(new FileReader(filename));
    }

    public static void createEmptyXml(String filename) throws IOException {
        Assert.notBlank(filename);

        saveToXml(new XhtmlAutocompleteSettings(), filename);
    }

    public static void importFromSourceWorkspace(String sourcePath, String sitePath, String resultXml) throws IOException, SAXException, ParserConfigurationException, XPathExpressionException {
        XhtmlAutocompleteSettings settings = new XhtmlAutocompleteSettings();

        File root = new File(sourcePath);
        Assert.isTrue(root.exists());
        Assert.isTrue(root.isDirectory());

        Set<String> filesWith1Interfaces = new HashSet<String>();
        Set<String> filesWithoutInterfaces = new HashSet<String>();

        Collection<File> files = FileUtils.listFiles(root, new String[]{"xhtml"}, true);
        for (File f : files) {
            if (f.getName().endsWith(".xhtml")) {
                System.out.println("Processing file $f.absolutePath");

                Document xhtml = XmlUtils.parseXml(f);
                DocumentTraversal traversal = (DocumentTraversal) xhtml;
                NodeIterator it = traversal.createNodeIterator(xhtml.getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true);
                Node node = it.nextNode();


                while (node != null) {
                    String nodeName = node.getNodeName();
                    if (nodeName.equals("cc:interface")) {
                        String interfaceName = node.getAttributes().getNamedItem("name").getNodeValue();
                        Tag tag = new Tag();
                        tag.setName(interfaceName);

                        for (int i = 0; i < node.getChildNodes().getLength(); i++) {
                            Node child = node.getChildNodes().item(i);
                            String name = child.getAttributes().getNamedItem("name").getNodeValue();
                            String shortDescription = child.getAttributes().getNamedItem("shortDescription").getNodeValue();

                            TagAttribute tagAttribute = new TagAttribute();
                            tagAttribute.setName(name);
                            tagAttribute.setDescription(shortDescription);
                            tagAttribute.setMandatory(true);
                            tag.getAttributes().add(tagAttribute);
                        }

                        settings.getTags().add(tag);
                    }
                }
            }
        }

        root = new File(sitePath);
        Assert.isTrue(root.exists());
        Assert.isTrue(root.isDirectory());
        files = FileUtils.listFiles(root, new String[]{"xml"}, true);
        for (File f : files) {
            if (f.isDirectory()) return;
            if (f.getName().endsWith("!template.xml")) continue;
            if (f.getName().endsWith("site.xml")) continue;

            Document xhtml = XmlUtils.parseXml(f);
            XPath xpath = XPathFactory.newInstance().newXPath();
            XPathExpression expr = xpath.compile("/body/section");

            String tagName = null;//xhtml.body.section[0].attribute('name');
            String tagDescription = null;//xhtml.body.section[0].subsection[0].div.text();

            String tagSource = null;
//                if (xhtml.body.section.source) {
//                    tagSource = xhtml.body.section.source?.text();
//                } else {
//                    tagSource = xhtml.body.section.subsection[1].source.text();
//                }

            tagName = tagName.replace("webui:", "nx:");

            if (settings.getTagByName(tagName) != null) {
                StringBuilder sb = new StringBuilder();
                if (!StringUtils.isBlank(tagDescription)) {
                    sb.append("ОПИСАНИЕ\n");
                    sb.append(tagDescription);
                    sb.append("\n");
                }
                if (!StringUtils.isBlank(tagSource)) {
                    sb.append("ПРИМЕР ИСПОЛЬЗОВАНИЯ\n");
                    sb.append(tagSource);
                    sb.append("\n");
                }

                settings.getTagByName(tagName).setUsageExample(sb.toString());
            }
        }

        saveToXml(settings, resultXml);
    }

    public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException, XPathExpressionException {
        importFromSourceWorkspace("D:\\workspaces\\neoflex.faces\\neoflex.faces.components\\src\\main", "D:\\workspaces\\neoflex.faces\\neoflex.faces.components\\src\\site", "d:\\temp\\xhtml.xml");
    }
}
